#include "liveness.h"
#include "util.h"
#include "table.h"
#include "temp.h"
#include "flowgraph.h"

extern G_table node_ins;

static void enterLiveMap(G_table t, G_node flowNode,
        inout temps)
{
    G_enter(t, flowNode, temps);
}

static inout lookupLiveMap(G_table t,
        G_node flownode)
{
    return (inout) G_look(t, flownode);
}

// insert temps into set
void insertSet(U_set set, Temp_tempList list)
{
    Temp_tempList ptr = list;
    while(ptr)
    {
        U_setInsert(set, ptr->head);
        ptr = ptr->tail;
    }
}

// list of all temp variables
extern Temp_tempList templist;
extern U_edgeSet    adjSet;
extern U_set        precolored;
extern U_nbList        adjList;
extern int            degree[128];

// TODO: Assembly like "MOV [FP+1], 3" may causes problems
// as FP added to the src of the instruction in order to
// make the LiveGraph routine work. But when creating a
// conflict, the program depend on info of the src and
// des of a assembly instruction.

extern U_set worklistMoves;
extern G_table worklistN;
TAB_table temp_node;

G_node Live_tempToGnode(Temp_temp temp)
{
    return (G_node)TAB_look(temp_node, temp);
}

int printset(void* data)
{
    Temp_temp temp = (Temp_temp)data;
    printf("%s - ", Temp_look(Temp_name(), temp));
    return RESULT_OK;
}

struct Live_graph Live_liveness(G_graph flow)
{
    TAB_table node_set = TAB_empty();
    G_nodeList nodes = G_nodes(flow);
    G_nodeList ptr = nodes;
    bool changed = FALSE;
    struct Live_graph result;

    while(ptr)     //init liveness map
    {
        U_set setin = U_setNew();
        U_set setout = U_setNew();
//        U_set test = U_setNew();
        inout io= checked_malloc(sizeof(*io));
        io->in = setin;
        io->out = setout;

        enterLiveMap(node_set, ptr->head, io);
        ptr = ptr->tail;
    }

    // calculate the in[n] and out[n]
    do
    {
        int i;
        int countin, countout;
        int count = 0;

        ptr = nodes;
        changed = FALSE;
        while (ptr)
        {
            inout io = lookupLiveMap(node_set, ptr->head);
            U_set def, use, temp1, temp2;
            G_nodeList succ;


            countin = U_setGetCount(io->in);
            countout = U_setGetCount(io->out);
            temp1 = U_setNew();
            temp2 = U_setNew();
            def = U_setNew();
            use = U_setNew();

            insertSet(def, FG_def(ptr->head));
            insertSet(use, FG_use(ptr->head));

            U_setSub3(temp1, io->out, def);
            U_setAdd3(io->in, use, temp1);

            U_setDestroy( & def);
            U_setDestroy( & use);
            U_setDestroy( & temp1);

            succ = G_succ(ptr->head);
            while(succ)
            {
                U_set sin = lookupLiveMap(node_set, succ->head)->in;
                 U_setAdd2(temp2, sin);
                succ = succ->tail;
            }
            U_setDestroy( & io->out);
            io->out = temp2;

            if (countin != U_setGetCount(io->in)
                || countout != U_setGetCount(io->out))
                changed = TRUE;

#ifdef _DEBUG
            printf("[%d]\tin: ", count++);
            if (TAB_look(node_ins, ptr->head))
            {
                U_setForEach(io->in, printset);
                printf(" || out: ");
                U_setForEach(io->out, printset);
                printf("\n");
            }
#endif

            ptr = ptr->tail;
        }
#ifdef _DEBUG
        for (i=0; i<78; i++)
                printf("=");
        printf("\n");
#endif
    }while(changed);

    result.node_set = node_set;
    result.nodes = nodes;
    return result;
}


